/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package info.jerrinot.nettyloc;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.logging.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Utility that detects various properties specific to the current runtime
* environment, such as Java version and the availability of the
* {@code sun.misc.Unsafe} object.
* <p>
* You can disable the use of {@code sun.misc.Unsafe} if you specify
* the system property <strong>io.netty.noUnsafe</strong>.
*/
public final class PlatformDependent {
private static final ILogger logger = Logger.getLogger(PlatformDependent.class);
private static final Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN = Pattern.compile(
"\\s*-XX:MaxDirectMemorySize\\s*=\\s*([0-9]+)\\s*([kKmMgG]?)\\s*$");
private static final boolean HAS_UNSAFE = hasUnsafe0();
private static final long MAX_DIRECT_MEMORY = maxDirectMemory0();
private static final long ARRAY_BASE_OFFSET = arrayBaseOffset0();
static {
if (!hasUnsafe()) {
logger.info(
"Your platform does not provide complete low-level API for accessing direct buffers reliably. " +
"Unless explicitly requested, heap buffer will always be preferred to avoid potential system " +
"unstability.");
}
}
/**
* Return {@code true} if {@code sun.misc.Unsafe} was found on the classpath and can be used for acclerated
* direct memory access.
*/
public static boolean hasUnsafe() {
return HAS_UNSAFE;
}
/**
* Returns the maximum memory reserved for direct buffer allocation.
*/
public static long maxDirectMemory() {
return MAX_DIRECT_MEMORY;
}
/**
* Try to deallocate the specified direct {@link java.nio.ByteBuffer}. Please note this method does nothing if
* the current platform does not support this operation or the specified buffer is not a direct buffer.
*/
public static void freeDirectBuffer(ByteBuffer buffer) {
if (buffer.isDirect()) {
if (hasUnsafe()) {
PlatformDependent0.freeDirectBufferUnsafe(buffer);
} else {
PlatformDependent0.freeDirectBuffer(buffer);
}
}
}
public static long directBufferAddress(ByteBuffer buffer) {
return PlatformDependent0.directBufferAddress(buffer);
}
public static int getInt(Object object, long fieldOffset) {
return PlatformDependent0.getInt(object, fieldOffset);
}
public static long objectFieldOffset(Field field) {
return PlatformDependent0.objectFieldOffset(field);
}
public static void copyMemory(long srcAddr, long dstAddr, long length) {
PlatformDependent0.copyMemory(srcAddr, dstAddr, length);
}
public static void copyMemory(byte[] src, int srcIndex, long dstAddr, long length) {
PlatformDependent0.copyMemory(src, ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length);
}
public static void copyMemory(long srcAddr, byte[] dst, int dstIndex, long length) {
PlatformDependent0.copyMemory(null, srcAddr, dst, ARRAY_BASE_OFFSET + dstIndex, length);
}
private static boolean hasUnsafe0() {
boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false);
if (logger.isFinestEnabled()) {
logger.finest("-Dio.netty.noUnsafe: "+ noUnsafe);
}
if (noUnsafe) {
logger.finest("sun.misc.Unsafe: unavailable (io.netty.noUnsafe)");
return false;
}
// Legacy properties
boolean tryUnsafe;
if (SystemPropertyUtil.contains("io.netty.tryUnsafe")) {
tryUnsafe = SystemPropertyUtil.getBoolean("io.netty.tryUnsafe", true);
} else {
tryUnsafe = SystemPropertyUtil.getBoolean("org.jboss.netty.tryUnsafe", true);
}
if (!tryUnsafe) {
logger.finest("sun.misc.Unsafe: unavailable (io.netty.tryUnsafe/org.jboss.netty.tryUnsafe)");
return false;
}
try {
boolean hasUnsafe = PlatformDependent0.hasUnsafe();
if (logger.isFinestEnabled()) {
logger.finest("sun.misc.Unsafe: "+ (hasUnsafe ? "available" : "unavailable"));
}
return hasUnsafe;
} catch (Throwable t) {
return false;
}
}
private static long arrayBaseOffset0() {
if (!hasUnsafe()) {
return -1;
}
return PlatformDependent0.arrayBaseOffset();
}
private static long maxDirectMemory0() {
long maxDirectMemory = 0;
try {
// Try to get from sun.misc.VM.maxDirectMemory() which should be most accurate.
Class<?> vmClass = Class.forName("sun.misc.VM", true, ClassLoader.getSystemClassLoader());
Method m = vmClass.getDeclaredMethod("maxDirectMemory");
maxDirectMemory = ((Number) m.invoke(null)).longValue();
} catch (Throwable t) {
// Ignore
}
if (maxDirectMemory > 0) {
return maxDirectMemory;
}
try {
// Now try to get the JVM option (-XX:MaxDirectMemorySize) and parse it.
// Note that we are using reflection because Android doesn't have these classes.
Class<?> mgmtFactoryClass = Class.forName(
"java.lang.management.ManagementFactory", true, ClassLoader.getSystemClassLoader());
Class<?> runtimeClass = Class.forName(
"java.lang.management.RuntimeMXBean", true, ClassLoader.getSystemClassLoader());
Object runtime = mgmtFactoryClass.getDeclaredMethod("getRuntimeMXBean").invoke(null);
@SuppressWarnings("unchecked")
List<String> vmArgs = (List<String>) runtimeClass.getDeclaredMethod("getInputArguments").invoke(runtime);
for (int i = vmArgs.size() - 1; i >= 0; i --) {
Matcher m = MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN.matcher(vmArgs.get(i));
if (!m.matches()) {
continue;
}
maxDirectMemory = Long.parseLong(m.group(1));
switch (m.group(2).charAt(0)) {
case 'k': case 'K':
maxDirectMemory *= 1024;
break;
case 'm': case 'M':
maxDirectMemory *= 1024 * 1024;
break;
case 'g': case 'G':
maxDirectMemory *= 1024 * 1024 * 1024;
break;
}
break;
}
} catch (Throwable t) {
// Ignore
}
if (maxDirectMemory <= 0) {
maxDirectMemory = Runtime.getRuntime().maxMemory();
if (logger.isFinestEnabled()) {
logger.finest("maxDirectMemory: +"+maxDirectMemory+" bytes (maybe)");
}
} else {
if (logger.isFinestEnabled()) {
logger.finest("maxDirectMemory: "+maxDirectMemory+" bytes");
}
}
return maxDirectMemory;
}
private PlatformDependent() {
// only static method supported
}
}